package com.bringspring.oauth.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.emoji.EmojiUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.bringspring.common.base.UserInfo;
import com.bringspring.common.config.ConfigValueUtil;
import com.bringspring.common.constant.MsgCode;
import com.bringspring.common.database.data.DataSourceContextHolder;
import com.bringspring.common.database.model.TenantLinkModel;
import com.bringspring.common.database.model.TenantVO;
import com.bringspring.common.model.login.*;
import com.bringspring.common.util.*;
import com.bringspring.common.util.treeutil.ListToTreeUtil;
import com.bringspring.common.util.treeutil.SumTree;
import com.bringspring.common.util.treeutil.newtreeutil.TreeDotUtils;
import com.bringspring.common.util.wxutil.HttpUtil;
import com.bringspring.oauth.model.DingUserInfoModel;
import com.bringspring.oauth.model.PcUserVO;
import com.bringspring.oauth.service.LoginService;
import com.bringspring.system.base.entity.SysConfigEntity;
import com.bringspring.system.base.exception.LoginException;
import com.bringspring.system.base.model.button.ButtonModel;
import com.bringspring.system.base.model.column.ColumnModel;
import com.bringspring.system.base.model.dingding.DingUserModel;
import com.bringspring.system.base.model.form.ModuleFormModel;
import com.bringspring.system.base.model.module.ModuleModel;
import com.bringspring.system.base.model.resource.ResourceModel;
import com.bringspring.system.base.model.systemconfig.QyChatModel;
import com.bringspring.system.base.model.systemconfig.SystemInfo;
import com.bringspring.system.base.service.SysConfigService;
import com.bringspring.system.base.util.Props;
import com.bringspring.system.external.bean.WeComModel;
import com.bringspring.system.external.bean.linkedcorp.MyWxCpLinkedCorpUser;
import com.bringspring.system.external.config.mutil.WxCpConfiguration;
import com.bringspring.system.external.service.WxCpCorpService;
import com.bringspring.system.external.service.WxCpLinkedCorpService;
import com.bringspring.system.external.service.impl.MyWxCpLinkedCorpServiceImpl;
import com.bringspring.system.external.util.ValidateCommonUtil;
import com.bringspring.system.message.entity.SynThirdInfoEntity;
import com.bringspring.system.message.service.SynThirdInfoService;
import com.bringspring.system.message.util.SynQyWebChatUtil;
import com.bringspring.system.message.util.SynThirdConsts;
import com.bringspring.system.permission.constant.PermissionConst;
import com.bringspring.system.permission.entity.*;
import com.bringspring.system.permission.model.authorize.AuthorizeVO;
import com.bringspring.system.permission.service.*;
import com.bringspring.visualdev.portal.model.PortalSelectModel;
import com.bringspring.visualdev.portal.service.PortalService;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpOAuth2ServiceImpl;
import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
import me.chanjar.weixin.cp.bean.WxCpUser;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

import static com.bringspring.system.external.constant.WxCpSysConfigConsts.TARGET_CHAR;
import static com.bringspring.system.message.util.SynThirdConsts.*;

/**
 * @author 开发平台组
 * @version V1.0.0
 * @copyright 股份有限公司
 * @date 2021/3/16
 */
@Service
public class LoginServiceImpl implements LoginService {

    protected Log log = LogFactory.getLog(this.getClass());

    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private Props props;
    @Autowired
    private UserProvider userProvider;
    @Autowired
    private UserService userService;
    @Autowired
    private UserRelationService userRelationService;
    @Autowired
    private OrganizeService organizeService;
    @Autowired
    private PositionService positionService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private AuthorizeService authorizeService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private PortalService portalService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private CacheKeyUtil cacheKeyUtil;
    @Autowired
    private OrganizeRelationService organizeRelationService;
    @Autowired
    private SynThirdInfoService synThirdInfoService;
    /**
     * 取出线程池
     */
    @Autowired
    private Executor threadPoolExecutor;

    @Autowired
    private WxCpCorpService wxCpCorpService;
    @Autowired
    WxCpConfiguration wxCpConfiguration;
    @Autowired
    ValidateCommonUtil validateCommonUtil;
    @Autowired
    WxCpLinkedCorpService wxCpLinkedCorpService;

    @Override
    public UserInfo checkTenant(LoginForm loginForm) throws LoginException {
        UserInfo userInfo = new UserInfo();
        String tenantId = "";
        if (Boolean.parseBoolean(configValueUtil.getMultiTenancy())) {
            String[] tenantAccount = loginForm.getAccount().split("\\@");
            tenantId = tenantAccount.length == 1 ? loginForm.getAccount() : tenantAccount[0];
            loginForm.setAccount(tenantAccount.length == 1 ? "admin" : tenantAccount[1]);
            if (tenantAccount.length > 2 || tenantId.length() > 11) {
                throw new LoginException(MsgCode.LOG102.get());
            }
            Map<String, Object> resulList;
            //切换成租户库
            JSONObject object;
            if (props.getPortUrl().contains("https")) {
                object = HttpUtil.httpRequest(props.getPortUrl() + tenantId, "GET", null);
            } else {
                object = HttpUtil.httpRequest(props.getPortUrl() + tenantId, "GET", null);
            }
            if (object == null || "500".equals(object.get("code").toString())) {
                throw new LoginException(MsgCode.LOG105.get());
            }
            if ("400".equals(object.getString("code"))) {
                throw new LoginException(object.getString("msg"));
            }
            resulList = JsonUtil.stringToMap(object.getString("data"));

            // 租户库名
            String name = null;
            if (resulList.get("java") != null) {
                name = String.valueOf(resulList.get("java"));
            } else {
                // 转换成租户信息模型
                TenantVO vo = JsonUtil.getJsonToBean(resulList, TenantVO.class);
                List<TenantLinkModel> linkList = vo.getLinkList();
                if (linkList != null && linkList.size() > 0) {
                    name = "true";
                    redisUtil.insert(tenantId, JsonUtil.getObjectToString(linkList), -1);
                } else {
                    name = vo.getDbName();
                }
            }
            userInfo.setTenantId(tenantId);
            userInfo.setTenantDbConnectionString(name);
            DataSourceContextHolder.setDatasource(tenantId, name);
        }
        return userInfo;
    }

    @Override
    public UserInfo userInfo(UserInfo userInfo, UserEntity userEntity, BaseSystemInfo sysConfigInfo) throws LoginException {
        userInfo.setIsAdministrator(BooleanUtil.toBoolean(String.valueOf(userEntity.getIsAdministrator())));
        userInfo.setUserId(userEntity.getId());
        userInfo.setUserAccount(userEntity.getAccount());
        userInfo.setUserName(userEntity.getRealName());
        userInfo.setRealName(userEntity.getRealName());
        userInfo.setUserIcon(userEntity.getHeadIcon());
        userInfo.setOrganizeId(userEntity.getOrganizeId());
        userInfo.setPortalId(userEntity.getPortalId());
        userInfo.setIsAdministrator(BooleanUtil.toBoolean(String.valueOf((userEntity.getIsAdministrator()))));

        // 添加过期时间
        String time = sysConfigInfo.getTokenTimeout();
        Integer minu = Integer.valueOf(time);
        userInfo.setOverdueTime(DateUtil.dateAddMinutes(null, minu));
        userInfo.setTokenTimeout(minu);

        userInfo.setLoginTime(DateUtil.getmmNow());
        userInfo.setLoginPlatForm(ServletUtils.getUserAgent());
        userInfo.setPrevLoginTime(userEntity.getPrevLogTime());
        userInfo.setPrevLoginIpAddress(userEntity.getPrevLogIp());
        userInfo.setPrevLoginIpAddressName(IpUtil.getIpCity(userEntity.getPrevLogIp()));

        // 生成id
        String token = RandomUtil.uuId();
        userInfo.setId(cacheKeyUtil.getLoginToken(userInfo.getTenantId()) + token);
        return userInfo;
    }

    private UserCommonInfoVO data(UserInfo userInfo) {
        //公司Id
        List<OrganizeEntity> list = organizeService.getList();
        UserEntity userEntity = userService.getInfo(userInfo.getUserId());
        // 防止出现空指针
        userEntity = userEntity != null ? userEntity : new UserEntity();
        userInfo.setManagerId(userInfo.getManagerId());
        boolean b = userInfo.getIsAdministrator();
        this.userInfo(userInfo, userInfo.getUserId(), b, userEntity);
        userInfo.setSubOrganizeIds(this.getSubOrganizeIds(list, userInfo.getOrganizeId(), b));
        List<String> subordinateIdsList = userService.getListByManagerId(userInfo.getUserId(), null).stream().map(UserEntity::getId).collect(Collectors.toList());
        userInfo.setSubordinateIds(subordinateIdsList);
        userInfo.setLoginTime(DateUtil.getmmNow());
        userInfo.setLoginPlatForm(ServletUtils.getUserAgent());
        redisUtil.insert(userInfo.getId(), userInfo, DateUtil.getTime(userInfo.getOverdueTime()) - DateUtil.getTime(new Date()));
        BaseSystemInfo baseSystemInfo = sysConfigService.getSysInfo();
        UserCommonInfoVO infoVO = JsonUtil.getJsonToBean(userInfo(userInfo, baseSystemInfo), UserCommonInfoVO.class);
        // 角色数组
        infoVO.setRoleIds(userInfo.getRoleIds());
        // 角色名称
        StringBuilder roleName = new StringBuilder();
        for (RoleEntity entity : roleService.getListByIds(userInfo.getRoleIds())) {
            roleName.append("," + entity.getFullName());
        }
        if (roleName.length() > 0) {
            infoVO.setRoleName(roleName.toString().replaceFirst(",", ""));
        }
        // 主管
        UserEntity info = userService.getInfo(userEntity.getManagerId());
        if (info != null) {
            infoVO.setManager(info.getRealName() + "/" + info.getAccount());
        }

        // 手机
        infoVO.setMobilePhone(userEntity.getMobilePhone());
        // 邮箱
        infoVO.setEmail(userEntity.getEmail());
        // 生日
        infoVO.setBirthday(userEntity.getBirthday() != null ? userEntity.getBirthday().getTime() : null);
        // 姓名
        infoVO.setUserName(userEntity.getRealName());
        //组织
        OrganizeEntity organizeEntity = organizeService.getInfo(userInfo.getDepartmentId());
        String organizeName = null;
        String departmentId = null;
        String departmentName = null;
        if (organizeEntity != null) {
            organizeName = organizeEntity.getFullName();
            if (StringUtils.isNotEmpty(organizeEntity.getOrganizeIdTree())) {
                String[] split = organizeEntity.getOrganizeIdTree().split(",");
                departmentId = split.length > 0 ? split[split.length - 1] : "";
                departmentName = organizeService.getFullNameByOrgIdTree(organizeEntity.getOrganizeIdTree(), "/");
            }
        }
        infoVO.setOrganizeName(organizeName);
        // 部门id
        infoVO.setDepartmentId(departmentId);
        // 部门名称
        infoVO.setDepartmentName(departmentName);
        return infoVO;
    }

    /**
     * 递归找他的上级
     */
    public void getOrganizeName(List<OrganizeEntity> OrganizeList, String organizeId) throws Exception {
        List<OrganizeEntity> OrganizeList2 = OrganizeList.stream().filter(t -> organizeId.equals(t.getId())).collect(Collectors.toList());
        if (OrganizeList2.size() > 0) {
            for (OrganizeEntity organizeEntity : OrganizeList2) {
                if (organizeEntity.getParentId().equals("-1")) {
                    //父级为-1时候退出
                    throw new Exception(JSON.toJSONString(organizeEntity));
                }
            }
            for (OrganizeEntity orgSub : OrganizeList2) {
                getOrganizeName(OrganizeList, orgSub.getParentId());
            }
        }
    }
    @Override
    public UserEntity isExistUser(String account) throws LoginException {

        // 得到系统配置
        BaseSystemInfo sysConfigInfo = sysConfigService.getSysInfo();
        UserEntity userEntity = userService.getUserByAccount(account);
        if (userEntity == null) {
            throw new LoginException(MsgCode.LOG003.get());
        }
        //判断是否组织、岗位、角色、部门主管是否为空，为空则抛出异常
        //判断是否为管理员，是否为Admin(Admin为最高账号，不受限制)
        if (!"admin".equals(userEntity.getId()) || userEntity.getIsAdministrator() != 1) {
            //组织id为空则直接抛出异常
            if (StringUtils.isEmpty(userEntity.getOrganizeId())) {
                throw new LoginException(MsgCode.LOG004.get());
            }
            // 岗位id为空则直接抛出异常
//            if (StringUtil.isEmpty(userEntity.getPositionId())) {
//                throw new LoginException("账号异常，请联系管理员修改所属岗位信息");
//            }
//            //角色id为空则直接抛出异常
//            if (StringUtil.isEmpty(userEntity.getRoleId())) {
//                throw new LoginException("账号异常，请联系管理员修改角色信息");
//            }
//            //主管id为空则直接抛出异常
//            if (StringUtil.isEmpty(userEntity.getManagerId())) {
//                throw new LoginException("账号异常，请联系管理员修改主管信息");
//            }
        }
        if (userEntity.getIsAdministrator() == 0) {
            if (userEntity.getEnabledMark() == null) {
                throw new LoginException(MsgCode.LOG005.get());
            }
            if (userEntity.getEnabledMark() == 0) {
                throw new LoginException(MsgCode.LOG006.get());
            }
        }
        if (userEntity.getDeleteMark() != null && userEntity.getDeleteMark() == 1) {
            throw new LoginException(MsgCode.LOG007.get());
        }
        //安全验证
        String ipAddr = IpUtil.getIpAddr();
        // 判断白名单
        if (!"admin".equals(userEntity.getId()) && "1".equals(sysConfigInfo.getWhitelistSwitch())) {
            List<String> ipList = Arrays.asList(sysConfigInfo.getWhitelistIp().split(","));
            if (!ipList.contains(ipAddr)) {
                throw new LoginException(MsgCode.LOG010.get());
            }
        }
        //判断用户所属的角色是否被禁用
        if (userEntity.getIsAdministrator() != 1) {
            if (userEntity.getIsAdministrator() == 0) {
                List<RoleEntity> userAllRole = roleService.getListByUserId(userEntity.getId());
                boolean permissionFlag = false;
                for (RoleEntity role : userAllRole) {
                    if (role != null && role.getEnabledMark() != null && role.getEnabledMark() != 0) {
                        permissionFlag = true;
                        break;
                    }
                }
                if (!permissionFlag) {
                    throw new LoginException(MsgCode.LOG011.get());
                }
            } else {
                throw new LoginException(MsgCode.LOG011.get());
            }
        }
        // 判断当前账号是否被锁定
        Integer lockMark = userEntity.getEnabledMark();
        if (Objects.nonNull(lockMark) && lockMark == 2) {
            // 获取解锁时间
            Date unlockTime = userEntity.getUnlockTime();
            // 账号锁定
            if (Objects.isNull(unlockTime)) {
                throw new LoginException(MsgCode.LOG012.get());
            }
            // 延迟登陆锁定
            long millis = System.currentTimeMillis();
            if (unlockTime.getTime() > millis) {
                // 转成分钟
                int time = (int) ((unlockTime.getTime() - millis) / (1000 * 60));
                throw new LoginException(MsgCode.LOG013.get().replace("{time}", Integer.toString(time + 1)));
            }
        }
        return userEntity;
    }

    /**
     * 组装登录信息
     *
     * @param userEntity
     * @return
     * @throws LoginException
     */
    @Override
    public UserInfo loginProcess(UserEntity userEntity) throws LoginException {
        UserInfo userInfo = new UserInfo();
        // 得到系统配置
        BaseSystemInfo systemInfo = sysConfigService.getSysInfo();

        userInfo = this.userInfo(userInfo, userEntity, systemInfo);

        //移除在线
        if ("1".equals(String.valueOf(systemInfo.getSingleLogin()))) {
            userProvider.removeWebSocket(userInfo);
        }
        //写入会话
        userProvider.add(userInfo);
        // 账号密码正确后重置错误次数
        userEntity.setLogErrorCount(0);
        userEntity.setUnlockTime(null);
        //修改前一次登陆时间等信息
        userEntity.setPrevLogIp(IpUtil.getIpAddr());
        userEntity.setPrevLogTime(DateUtil.getNowDate());
        userEntity.setLastLogIp(IpUtil.getIpAddr());
        userEntity.setLastLogTime(DateUtil.getNowDate());
        userEntity.setLogSuccessCount(userEntity.getLogSuccessCount() != null ? userEntity.getLogSuccessCount() + 1 : 1);
        userService.updateById(userEntity);


        return userInfo;
    }

    /**
     * 获取用户登陆信息
     *
     * @return
     */
    @Override
    public PcUserVO getCurrentUser(String type, String applicationId) {
        UserInfo userInfo = userProvider.get();
        UserCommonInfoVO infoVO = this.data(userInfo);
        AuthorizeVO authorizeModel = authorizeService.getAuthorize(false);
        // 获取菜单权限
        List<ModuleModel> moduleList = authorizeModel.getModuleList();
        List<ModuleModel> menuList = null;
        List<ModuleModel> systemList = null;
        // 判断是否为Web "0".equals(t.getType())判断系统
        if (StringUtils.isEmpty(type)) {
            systemList = moduleList.stream().filter(t -> "Web".equals(t.getCategory()) && "0".equals(String.valueOf(t.getType()))).sorted(Comparator.comparing(ModuleModel::getSortCode)).collect(Collectors.toList());
            menuList = moduleList.stream().filter(t -> "Web".equals(t.getCategory()) && !"0".equals(String.valueOf(t.getType()))).sorted(Comparator.comparing(ModuleModel::getSortCode)).collect(Collectors.toList());
        } else {
            systemList = moduleList.stream().filter(t -> "App".equals(t.getCategory()) && "0".equals(String.valueOf(t.getType()))).sorted(Comparator.comparing(ModuleModel::getSortCode)).collect(Collectors.toList());
            menuList = moduleList.stream().filter(t -> "App".equals(t.getCategory())).sorted(Comparator.comparing(ModuleModel::getSortCode)).collect(Collectors.toList());
        }

        /**
         * 如果没有传入applicationId作为系统id;则默认查询一个有菜单的系统id
         */

        List<ModuleModel> finalMenuList = menuList;
        List<ModuleModel> authSystemList = systemList.stream().filter(t -> finalMenuList.stream().filter(m -> t.getId().equals(m.getParentId())).findAny().isPresent()).collect(Collectors.toList());
        if (StringUtils.isEmpty(applicationId) && StringUtils.isEmpty(type)) {
            applicationId = authSystemList.get(0).getId();
        } else if ("App".equals(type)) {
            //移动端如果使用多系统模式，这里就要去掉
            applicationId = "-1";
        }
        /**
         * 如果默认的applicationId没有权限，则自动切换到有权限的系统上
         */
        if (StringUtils.isNotEmpty(applicationId)) {
            String finalApplicationId = applicationId;
            boolean b = systemList.stream().anyMatch(m -> m.getId().equals(finalApplicationId));
            if (!b) {
                applicationId = authSystemList.get(0).getId();
            }
        }
        //转成tree的方法
        List<UserMenuModel> menu = JsonUtil.getJsonToList(menuList, UserMenuModel.class);
        List<SumTree<UserMenuModel>> menus = TreeDotUtils.convertListToTreeDot(menu, applicationId);

        //返回前台tree的list
        List<MenuTreeVO> list = JsonUtil.getJsonToList(menus, MenuTreeVO.class);
        //岗位
        List<String> posiList = Arrays.asList(userInfo.getPositionIds());
        List<PositionEntity> positionList = positionService.getPositionName(posiList);
        List<UserPositionVO> positionVO = new ArrayList<>();
        for (PositionEntity positionEntity : positionList) {
            UserPositionVO userPositionVO = new UserPositionVO();
            userPositionVO.setName(positionEntity.getFullName());
            userPositionVO.setId(positionEntity.getId());
            positionVO.add(userPositionVO);
        }
        List<PermissionModel> models = new ArrayList<>();
        for (ModuleModel moduleModel : menuList) {
            PermissionModel model = new PermissionModel();
            model.setModelId(moduleModel.getId());
            model.setModuleName(moduleModel.getFullName());
            List<ButtonModel> buttonModels = authorizeModel.getButtonList().stream().filter(t -> moduleModel.getId().equals(t.getModuleId())).collect(Collectors.toList());
            List<ColumnModel> columnModels = authorizeModel.getColumnList().stream().filter(t -> moduleModel.getId().equals(t.getModuleId())).collect(Collectors.toList());
            List<ResourceModel> resourceModels = authorizeModel.getResourceList().stream().filter(t -> moduleModel.getId().equals(t.getModuleId())).collect(Collectors.toList());
            List<ModuleFormModel> moduleFormModels = authorizeModel.getFormsList().stream().filter(t -> moduleModel.getId().equals(t.getModuleId())).collect(Collectors.toList());
            model.setButton(JsonUtil.getJsonToList(buttonModels, PermissionVO.class));
            model.setColumn(JsonUtil.getJsonToList(columnModels, PermissionVO.class));
            model.setResource(JsonUtil.getJsonToList(resourceModels, PermissionVO.class));
            model.setForm(JsonUtil.getJsonToList(moduleFormModels, PermissionVO.class));
            if (moduleModel.getType() != 1) {
                models.add(model);
            }
        }
        //初始化接口权限
        if (configValueUtil.getEnablePreAuth()) {
            initSecurityAuthorities(authorizeModel, userInfo);
        }

        //门户
        UserEntity info = userService.getInfo(userInfo.getUserId());
        if (StringUtils.isEmpty(info.getPortalId())) {
            List<PortalSelectModel> portalList = portalService.getList("1");
            if (portalList.size() > 0) {
                infoVO.setPortalId(portalList.get(0).getId());
            }
        } else {
            infoVO.setPortalId(info.getPortalId());
        }
        infoVO.setPositionIds(positionVO);
        BaseSystemInfo sysInfo = sysConfigService.getSysInfo();
        SystemInfo jsonToBean = JsonUtil.getJsonToBean(sysInfo, SystemInfo.class);
        PcUserVO userVO = new PcUserVO(systemList, list, models, infoVO, jsonToBean);
        userVO.setPermissionList(models);
//        userVO.getUserInfo().setHeadIcon(UploaderUtil.uploaderImg(userInfo.getUserIcon()));
        userVO.getUserInfo().setHeadIcon(userInfo.getUserIcon());
        return userVO;
    }

    @Override
    public String getAccountByWeComCode(String code, String cropId) throws Exception {
        SysConfigEntity weComInfo = sysConfigService.getConfigByKeyName("weCom");
        List<QyChatModel> jsonToList = JsonUtil.getJsonToList(weComInfo.getKeyValue(), QyChatModel.class);
        QyChatModel qyhCorpId = jsonToList.stream().filter(v -> cropId.equals(v.getQyhCorpId())).collect(Collectors.toList()).get(0);

        String corpId = qyhCorpId.getQyhCorpId();
        String corpSecret = qyhCorpId.getQyhCorpSecret();
        String access_token = "";
        UserEntity userEntity = new UserEntity();
        try {
            // 获取Token值
            JSONObject tokenObject = SynQyWebChatUtil.getAccessToken(corpId, corpSecret);
            if (!tokenObject.getBoolean("code")) {
                throw new LoginException("获取企业微信access_token失败！Result:" + tokenObject.toJSONString());
            }
            access_token = tokenObject.getString("access_token");
            JSONObject rstObj = SynQyWebChatUtil.getUserId(access_token, code);
            String linkedcorpAgentString = String.valueOf(rstObj.get("userid"));
            if (StringUtils.isEmpty(linkedcorpAgentString)) {
                throw new LoginException("获取企业微信当前登录账户失败，请重试！Result:" + rstObj.toJSONString());
            }
            // 从同步表获取对应的企业微信ID
            SynThirdInfoEntity synThirdInfoEntity = synThirdInfoService.getInfoByThirdObjId(SynThirdConsts.THIRD_TYPE_QY, DATA_TYPE_USER, linkedcorpAgentString);
            //如果第三方表没有数据，则主动拉去
            if (ObjectUtil.isEmpty(synThirdInfoEntity)) {
                JSONObject weComUser = SynQyWebChatUtil.getLinkedcorpUserInfoById(access_token, linkedcorpAgentString);
                Map<String, Object> map = JsonUtil.stringToMap(String.valueOf(weComUser.get("userinfo")));
                // 新增
                // 判断是不是为空,需要挨个判断。
                if (!StringUtils.isNull(map.get("name"))) {
                    String realName = String.valueOf(map.get("name")).replaceAll("[^\u4e00-\u9fa5]", "");
                    userEntity.setRealName(realName);
                }

                if (!StringUtils.isNull(map.get("english_name"))) {
                    userEntity.setAccount(String.valueOf(map.get("english_name")));
                }
                // 快速查询
                if (!StringUtils.isNull(map.get("alias"))) {
                    userEntity.setQuickQuery(String.valueOf(map.get("alias")));
                }
                // 昵称
                if (!StringUtils.isNull(map.get("lias"))) {
                    userEntity.setNickName(String.valueOf(map.get("lias")));
                }
                // 账户用userID id
                if (!StringUtils.isNull(map.get("userid"))) {
                    userEntity.setAccount(String.valueOf(map.get("userid")));
                }

                String department1 = null;
                if (!StringUtils.isNull(map.get("department"))) {
//                    department1 = String.valueOf(map.get("department")).replaceAll("\\[", "").replaceAll("]", "");
                    JSONArray depts = (JSONArray) map.get("department");
                    String deptId = "";
                    if (depts.size() > 0) {
                        department1 = String.valueOf(depts.getString(0));
                        deptId = department1;
                        String[] deptSplit = department1.split("/");
                        if (deptSplit.length > 1) {
                            deptId = deptSplit[1];
                        }
                    }
                    userEntity.setOrganizeId(deptId);
                }
                if (!StringUtils.isNull(map.get("mobile"))) {
                    userEntity.setMobilePhone(String.valueOf(map.get("mobile")));
                }
                if (!StringUtils.isNull(map.get("email"))) {
                    userEntity.setEmail(String.valueOf(map.get("email")));
                }
                if (!StringUtils.isNull(map.get("address"))) {
                    userEntity.setPostalAddress(String.valueOf(map.get("address")));
                }
                if (!StringUtils.isNull(map.get("gender")) && !"0".equals(String.valueOf(map.get("gender")))) {
                    userEntity.setGender(Integer.parseInt(String.valueOf(map.get("gender"))));
                } else {
                    userEntity.setGender(3);
                }
                if (!StringUtils.isNull(map.get("direct_leader"))) {
                    userEntity.setManagerId(String.valueOf(map.get("direct_leader")).replaceAll("\\[", "").replaceAll("]", ""));
                }

                if (!StringUtils.isNull(map.get("position"))) {
                    userEntity.setPositionId(String.valueOf(map.get("position")));
                }
                //获取头像  微信企业没传，暂定为默认
                userEntity.setHeadIcon("/api/file/Image/userAvatar/001.png");
                userEntity.setEnabledMark(1);
                //设置默认角色
                List<RoleEntity> listByEnCode = roleService.getListByEnCode(PermissionConst.SIMPLE_USER);
                userEntity.setRoleId(listByEnCode.get(0).getId());
                Boolean user = userService.createUser(userEntity);

                UserEntity finalUserEntity = userEntity;
                threadPoolExecutor.execute(() -> {
                    try {
                        //添加用户之后判断是否需要同步到企业微信
                        // 重构企业微信
//                        synThirdQyService.saveSynThirdInfoEntity(SynThirdConsts.OBJECT_OP_ADD, null, Integer.parseInt(SynThirdConsts.THIRD_TYPE_QY), Integer.parseInt(DATA_TYPE_USER), finalUserEntity.getId(), linkedcorpAgentString, SynThirdConsts.SYN_STATE_OK, "企业微信登陆时同步企业用户信息");
//                        synThirdQyService.saveSynThirdInfoEntity(SynThirdConsts.OBJECT_OP_ADD, null, Integer.parseInt(SynThirdConsts.THIRD_TYPE_QY),
//                                Integer.parseInt(SynThirdConsts.DATA_TYPE_ORG), userEntity.getOrganizeId(), finalDepartment, SynThirdConsts.SYN_STATE_OK, "企业微信登陆时同步");
                        //添加用户之后判断是否需要同步到钉钉
                    } catch (Exception e) {
                        log.error("添加用户之后同步失败到企业微信或钉钉失败，异常：" + e.getMessage());
                    }
                });
            } else {
                userEntity = userService.getInfo(synThirdInfoEntity.getSystemObjectId());
            }
            if (ObjectUtil.isEmpty(userEntity)) {
                throw new LoginException("企业微信未关联到用户！");
            }
            return userEntity.getAccount();
        } catch (Exception e) {
            e.printStackTrace();
            throw new LoginException(e.getMessage());
        }
    }


    @Override
    public String getAccountByWxCode(String weComCode, String corpId) {
        String returnAccount = null;
        if (StringUtils.isNotEmpty(corpId)) {
            /**
             * 获取到系统配置
             */
            final WeComModel weComModel = wxCpConfiguration.getWeComModel(corpId);
            if (weComModel == null) {
                throw new LoginException(String.format("未找到对应corpId=[%s]的配置，请核实！", corpId));
            } else {
                /**
                 * 通讯录secret
                 */
                final WxCpService wxCorpService = wxCpConfiguration.getCorpService(corpId);

                /**
                 * 应用secret
                 */
                String agentId = weComModel.getQyhAgentId();
                final WxCpService wxCpService = wxCpConfiguration.getCpService(corpId, Integer.valueOf(agentId));
                if (wxCpService == null) {
                    throw new LoginException(String.format("未找到对应corpId=[%s]、agentId=[%d]的配置，请核实！", corpId, agentId));
                } else {
                    try {
                        /**
                         * 获取访问用户身份
                         */
                        WxCpOauth2UserInfo oauthUserInfo =  wxCpService.getOauth2Service().getUserInfo(weComCode);
                        String userId = oauthUserInfo.getUserId();
                        if (StringUtils.isEmpty(userId)) {
                            throw new LoginException("获取企业微信当前访问用户身份失败！");
                        }
                        Boolean isLinkedCorp = weComModel.getIsLinkedCorp();
                        if (isLinkedCorp) {// 互联企业
                            // THIRD_TYPE_QY：第三方工具类型(1:企业微信;2:钉钉)、DATA_TYPE_USER：数据类型(1:组织(公司与部门);2:用户)
                            String thirdObjid;
                            if (StringUtils.isNotEmpty(userId) && userId.contains(TARGET_CHAR)) {
                                thirdObjid = userId;
                            } else {
                                thirdObjid = corpId + TARGET_CHAR + userId;
                            }
                            SynThirdInfoEntity synThirdInfoEntity =
                                    synThirdInfoService.getInfoByThirdObjId(THIRD_TYPE_QY, DATA_TYPE_USER, thirdObjid, corpId);
                            if (ObjectUtil.isNotEmpty(synThirdInfoEntity)) {
                                String systemObjectId = synThirdInfoEntity.getSystemObjectId();
                                UserEntity entity = userService.getInfo(systemObjectId);
                                if (entity != null) {
                                    /**
                                     * 获取账户成功
                                     */
                                    returnAccount = entity.getAccount();
                                }
                            }

                            /**
                             * 获取账户失败
                             * 获取企业微信信息
                             */
                            if (StringUtils.isEmpty(returnAccount)) {
                                // 注册账户
                                MyWxCpLinkedCorpServiceImpl myWxCpLinkedCorpService = new MyWxCpLinkedCorpServiceImpl();
                                myWxCpLinkedCorpService.setWxCpService(wxCpService);
                                /**
                                 * 获取互联企业成员详细信息
                                 * userid = corpid/userid, 如：wwc0366cea7d993696/joyliyi0218
                                 */
                                MyWxCpLinkedCorpUser qyuser = myWxCpLinkedCorpService.getLinkedCorpUser(thirdObjid);
                                String corpid = qyuser.getCorpId();
                                String userid = qyuser.getUserId();
                                if (ObjectUtil.isEmpty(qyuser) || StringUtils.isEmpty(corpid) || StringUtils.isEmpty(userid)) {
                                    throw new LoginException("获取互联企业成员详细信息失败！");
                                }

                                UserEntity userEntity = wxCpLinkedCorpService.registerSysAccount(qyuser, wxCpService);
                                if (ObjectUtil.isEmpty(userEntity)) {
                                    throw new LoginException("未关联到用户！");
                                }
                                returnAccount = userEntity.getAccount();
                            }
                        } else {// 多例企业
                            /**
                             * 通过第三方同步表获取系统账户
                             */
                            // THIRD_TYPE_QY：第三方工具类型(1:企业微信;2:钉钉)、DATA_TYPE_USER：数据类型(1:组织(公司与部门);2:用户)
                            String thirdObjid = userId;
                            SynThirdInfoEntity synThirdInfoEntity =
                                    synThirdInfoService.getInfoByThirdObjId(THIRD_TYPE_QY, DATA_TYPE_USER, thirdObjid, corpId);
                            if (ObjectUtil.isNotEmpty(synThirdInfoEntity)) {
                                String systemObjectId = synThirdInfoEntity.getSystemObjectId();
                                UserEntity entity = userService.getInfo(systemObjectId);
                                if (entity != null) {
                                    /**
                                     * 获取账户成功
                                     */
                                    returnAccount = entity.getAccount();
                                }
                            }

                            /**
                             * 获取账户失败
                             * 获取企业微信信息
                             */
                            if (StringUtils.isEmpty(returnAccount)) {
                                // 注册账户
                                WxCpUser wxCpUser = wxCpService.getUserService().getById(userId);
                                if (ObjectUtil.isEmpty(wxCpUser)) {
                                    throw new LoginException("获取企业成员详细信息失败！");
                                }

                                List<WxCpUser> users = new ArrayList<>();
                                users.add(wxCpUser);
                                /**
                                 * 保存到本地
                                 */
                                List<UserEntity> synThirdInfoEntities =
                                        wxCpCorpService.saveOrUpdateUserList(users, wxCpService);
                                if (CollectionUtil.isNotEmpty(synThirdInfoEntities)) {
                                    UserEntity entity = synThirdInfoEntities.get(0);
                                    returnAccount = entity.getAccount();
                                }
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new LoginException(e.getMessage());
                    }
                }
            }
        }
        return returnAccount;
    }

    public static com.aliyun.dingtalkoauth2_1_0.Client authClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

    /**
     * 获取用户token
     *
     * @param authCode
     * @return
     * @throws Exception
     */
    //接口地址：注意/auth与钉钉登录与分享的回调域名地址一致
    @Override
    public String getAccountByDingCode(String authCode) throws Exception {

        com.aliyun.dingtalkoauth2_1_0.Client client = authClient();
        GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()

                //应用基础信息-应用信息的AppKey,请务必替换为开发的应用AppKey
                .setClientId("dingqgbtl0pzm45qbonu")

                //应用基础信息-应用信息的AppSecret，,请务必替换为开发的应用AppSecret
                .setClientSecret("299RRMGBuD-Hsw9LE76DzJi-ApKmq3MABXm-tS8-plFFt189RrSJi_qB0U7tAot1").setCode(authCode).setGrantType("authorization_code");
        GetUserTokenResponse getUserTokenResponse = client.getUserToken(getUserTokenRequest);
        //获取用户个人token
        String accessToken = getUserTokenResponse.getBody().getAccessToken();
        DingUserInfoModel jsonToBean = JsonUtil.getJsonToBean(getUserinfo(accessToken), DingUserInfoModel.class);
        UserEntity infoByMobile = userService.getUserByAccount(jsonToBean.getMobile());
        return infoByMobile.getAccount();
    }

    @Override
    public String getAccountByDingCodeH5(String dingCode) throws Exception {

        DingTalkClient clientToken = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
        OapiGettokenRequest request = new OapiGettokenRequest();
        request.setAppkey("dingqgbtl0pzm45qbonu");
        request.setAppsecret("299RRMGBuD-Hsw9LE76DzJi-ApKmq3MABXm-tS8-plFFt189RrSJi_qB0U7tAot1");
        request.setHttpMethod("GET");
        OapiGettokenResponse response = clientToken.execute(request);
        System.out.println(response.getBody());
        Map<String, Object> stringObjectMap = JsonUtil.stringToMap(response.getBody());
        stringObjectMap.get("access_token");

        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
        OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
        req.setCode(dingCode);
        OapiV2UserGetuserinfoResponse rsp = client.execute(req, String.valueOf(stringObjectMap.get("access_token")));
        System.out.println(rsp.getBody());
        DingUserModel map = JsonUtil.getJsonToBean(String.valueOf(JsonUtil.stringToMap(rsp.getBody()).get("result")), DingUserModel.class);
        List<SynThirdInfoEntity> infoByThirdObjIds = synThirdInfoService.getInfoByThirdObjIds(THIRD_TYPE_DING, DATA_TYPE_USER, map.getUserid());
        UserEntity info = new UserEntity();
        if (!ObjectUtil.isEmpty(infoByThirdObjIds)) {
            info = userService.getInfo(infoByThirdObjIds.get(0).getSystemObjectId());

        }
        return info.getAccount();
    }


    public static com.aliyun.dingtalkcontact_1_0.Client contactClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkcontact_1_0.Client(config);
    }

    /**
     * 获取用户个人信息
     *
     * @param accessToken
     * @return
     * @throws Exception
     */
    public String getUserinfo(String accessToken) throws Exception {
        com.aliyun.dingtalkcontact_1_0.Client client = contactClient();
        GetUserHeaders getUserHeaders = new GetUserHeaders();
        getUserHeaders.xAcsDingtalkAccessToken = accessToken;
        //获取用户个人信息，如需获取当前授权人的信息，unionId参数必须传me
        String me = JSON.toJSONString(client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions()).getBody());
        System.out.println(me);
        return me;
    }

    /**
     * 初始化接口鉴权用的账号权限
     * 本接口插入权限缓存， MyRoleHierarchy中框架鉴权时动态调用获取权限列表
     *
     * @param authorizeModel
     * @param userInfo
     */
    private void initSecurityAuthorities(AuthorizeVO authorizeModel, UserInfo userInfo) {
        //接口权限
        Set<String> authorityList = new HashSet<>();
        Map<String, ModuleModel> moduleModelMap = authorizeModel.getModuleList().stream().filter(m -> {
            //添加菜单权限
            authorityList.add(m.getEnCode());
            return true;
        }).collect(Collectors.toMap(m -> m.getId(), m -> m));
        for (ModuleModel moduleModel : authorizeModel.getModuleList()) {
            String permissionKey = moduleModel.getEnCode();
            authorityList.add(permissionKey);
        }

        authorizeModel.getButtonList().stream().forEach(t -> {
            ModuleModel m = moduleModelMap.get(t.getModuleId());
            if (m != null) {
                authorityList.add(m.getEnCode() + "::" + t.getEnCode());
            }
        });
        authorizeModel.getColumnList().stream().forEach(t -> {
            ModuleModel m = moduleModelMap.get(t.getModuleId());
            if (m != null) {
                authorityList.add(m.getEnCode() + "::" + t.getEnCode());
            }
        });
        authorizeModel.getFormsList().stream().forEach(t -> {
            ModuleModel m = moduleModelMap.get(t.getModuleId());
            if (m != null) {
                authorityList.add(m.getEnCode() + "::" + t.getEnCode());
            }
        });

        //管理员都是用同一个缓存, 普通账号使用账号名,
        //权限列表：authorize_:租户_authorize_authorize_(admin|账号)
        //角色列表：authorize_:租户_authorize_role_(admin|账号)
        String authorityKey = CacheKeyUtil.USERAUTHORIZE + ":" + cacheKeyUtil.getUserAuthorize() + "authority_" + (userInfo.getIsAdministrator() ? "admin" : userInfo.getUserAccount());
        redisUtil.remove(authorityKey);
        redisUtil.insert(authorityKey, authorityList, 48 * 60 * 60L);
        if (userInfo.getRoleIds() != null && !userInfo.getRoleIds().isEmpty() || userInfo.getIsAdministrator()) {
            String rolesKey = CacheKeyUtil.USERAUTHORIZE + ":" + cacheKeyUtil.getUserAuthorize() + "role_" + (userInfo.getIsAdministrator() ? "admin" : userInfo.getUserAccount());
            List<RoleEntity> roles;
            if (userInfo.getIsAdministrator()) {
                roles = roleService.getList();
            } else {
                roles = roleService.getListByIds(userInfo.getRoleIds());
            }
            Set<String> roleAuthorityList = roles.stream().filter(r -> r.getEnabledMark().equals(1)).map(r -> "ROLE_" + r.getEnCode()).collect(Collectors.toSet());
            redisUtil.remove(rolesKey);
            redisUtil.insert(rolesKey, roleAuthorityList, 48 * 60 * 60L);
        }
    }

    /**
     * 获取角色
     *
     * @param userId
     * @return
     */
    private String[] getRoleId(String userId, boolean isAdmin) {
        List<UserRelationEntity> data = userRelationService.getListByUserId(userId);
        if (!isAdmin) {
            data = data.stream().filter(m -> "Role".equals(m.getObjectType())).collect(Collectors.toList());
        }
        List<String> list = data.stream().map(t -> t.getObjectId()).collect(Collectors.toList());
        return list.toArray(new String[list.size()]);
    }

    /**
     * 获取下属机构
     *
     * @param data
     * @param organizeId
     * @param isAdmin
     * @return
     */
    private String[] getSubOrganizeIds(List<OrganizeEntity> data, String organizeId, boolean isAdmin) {
        if (!isAdmin) {
            data = JsonUtil.getJsonToList(ListToTreeUtil.treeWhere(organizeId, data), OrganizeEntity.class);
        }
        List<String> list = data.stream().map(t -> t.getId()).collect(Collectors.toList());
        return list.toArray(new String[list.size()]);
    }

    /**
     * 获取岗位
     *
     * @param userId
     * @return
     */
    private String[] getPositionId(String userId, boolean isAdmin) {
        //获取list
        List<UserRelationEntity> data = userRelationService.getListByUserId(userId);
        //获取一个字段的值
        List<String> list = data.stream().filter(m -> "Position".equals(m.getObjectType())).map(t -> t.getObjectId()).collect(Collectors.toList());
        return list.toArray(new String[list.size()]);
    }

    /**
     * 赋值
     *
     * @param userInfo
     * @param userId
     * @param isAdmin
     */
    private void userInfo(UserInfo userInfo, String userId, boolean isAdmin, UserEntity userEntity) {
        // 得到用户和组织的关系
        List<UserRelationEntity> data = userRelationService.getListByUserIdAndObjType(userId, PermissionConst.ORGANIZE);
        // 组织id
        String organizeId = "";
        String departmentId = "";
        List<String> roleIdList = new ArrayList<>();
        // 判断当前组织是否有权限
        if (!organizeRelationService.checkBasePermission(userEntity.getId(), userEntity.getOrganizeId())) {
            if (data.size() > 0) {
                // 得到组织id
                departmentId = organizeRelationService.autoGetMajorOrganizeId(userId, data.stream().map(UserRelationEntity::getObjectId).collect(Collectors.toList()), userEntity.getOrganizeId());

            }
        } else {
            // 如果有权限
            departmentId = userEntity.getOrganizeId();
            if (isAdmin) {
                roleIdList = data.stream().map(t -> t.getObjectId()).collect(Collectors.toList());
            }
        }
        OrganizeEntity companyListById = organizeService.getDirectlyUnderCompanyById(departmentId);
        organizeId = companyListById.getId();
        // 获取用户的角色
        List<UserRelationEntity> listByObjectId = userRelationService.getListByUserId(userInfo.getUserId(), PermissionConst.ROLE);
        // 判断哪个角色是当前组织下的
        List<String> collect = listByObjectId.stream().map(UserRelationEntity::getObjectId).collect(Collectors.toList());
        // 如果有全局的角色则先赋值给权限集合
        for (String roleId : collect) {
            // 得到角色
            RoleEntity info = roleService.getInfo(roleId);
            if (info != null && "1".equals(String.valueOf(info.getGlobalMark()))) {
                roleIdList.add(info.getId());
                continue;
            }
            // 判断哪些角色是当前组织的

            Boolean exist = organizeRelationService.existByObejctIdAndOrgIdAndObjectType(organizeId, roleId, PermissionConst.ROLE);
            if (exist) {
                roleIdList.add(roleId);
            }
        }
        // 赋值岗位
        List<String> positionList = data.stream().filter(m -> "Position".equals(m.getObjectType())).map(t -> t.getObjectId()).collect(Collectors.toList());
        Set<String> id = new LinkedHashSet<>();
        String[] position = StringUtils.isNotEmpty(userEntity.getPositionId()) ? userEntity.getPositionId().split(",") : new String[]{};
        List<String> positions = positionList.stream().filter(t -> Arrays.asList(position).contains(t)).collect(Collectors.toList());
        id.addAll(positions);
        id.addAll(positionList);
        String[] positionId = id.toArray(new String[id.size()]);
        userInfo.setOrganizeId(organizeId);
        userInfo.setDepartmentId(departmentId);
        userInfo.setRoleIds(roleIdList);
        userInfo.setPositionIds(positionId);
        // 修改用户信息
//        userEntity.setOrganizeId(organizeId);
        String positionId1 = organizeRelationService.autoGetMajorPositionId(userId, organizeId, userEntity.getPositionId());
        userEntity.setPositionId(positionId1);
        userService.updateById(userEntity);
    }


    /**
     * 登录信息
     *
     * @param userInfo   回话信息
     * @param systemInfo 系统信息
     * @return
     */
    private Map<String, Object> userInfo(UserInfo userInfo, BaseSystemInfo systemInfo) {
        Map<String, Object> dictionary = new HashMap<>(16);
        dictionary.put("userId", userInfo.getUserId());
        dictionary.put("userAccount", userInfo.getUserAccount());
        dictionary.put("userName", userInfo.getRealName());
        dictionary.put("icon", userInfo.getUserIcon());
        dictionary.put("portalId", userInfo.getPortalId());
        dictionary.put("gender", userInfo.getUserGender());
        dictionary.put("organizeId", userInfo.getOrganizeId());
        dictionary.put("prevLogin", systemInfo.getLastLoginTimeSwitch() == 1 ? 1 : 0);
        dictionary.put("prevLoginTime", userInfo.getPrevLoginTime());
        dictionary.put("prevLoginIPAddress", userInfo.getPrevLoginIpAddress());
        dictionary.put("prevLoginIPAddressName", userInfo.getPrevLoginIpAddressName());
        dictionary.put("serviceDirectory", configValueUtil.getServiceDirectoryPath());
        dictionary.put("webDirectory", configValueUtil.getCodeAreasName());
        return dictionary;
    }

}
